package com.xy6.dpdemo.book.delegate.cglib;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import net.sf.cglib.beans.BeanGenerator;
import net.sf.cglib.beans.ImmutableBean;
import net.sf.cglib.core.KeyFactory;
import net.sf.cglib.proxy.CallbackHelper;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.FixedValue;
import net.sf.cglib.proxy.InvocationHandler;
import net.sf.cglib.proxy.NoOp;
import net.sf.cglib.reflect.FastClass;
import net.sf.cglib.reflect.FastMethod;
import net.sf.cglib.reflect.MethodDelegate;

/**
 * cglib中各类用法示例
 * 
 * @author zhang
 * @since 2018-04-29
 */
public class SampleClassTest {

	public static void testFixedValue(){
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(SampleClass.class);
		enhancer.setCallback(new FixedValue(){
			@Override
			public Object loadObject() throws Exception {
				return "hello cglib";
			}
		});
		SampleClass proxy = (SampleClass)enhancer.create();
		System.out.println(proxy.test("abc"));
		System.out.println(proxy.toString());
		System.out.println(proxy.getClass());
		System.out.println(proxy.hashCode());
	}
	
	public static void testInvocationHander(){
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(SampleClass.class);
		enhancer.setCallback(new InvocationHandler(){
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				if(method.getDeclaringClass() != Object.class && method.getReturnType() == String.class){
					return "hello cglib";
				} else {
					throw new RuntimeException("do not know what to do");
				}
			}
		});
		SampleClass sample = (SampleClass)enhancer.create();
		System.out.println(sample.test(null));
		System.out.println(sample.toString());
	}
	
	public static void testCallbackFilter() throws Exception {
		Enhancer enhancer = new Enhancer();
		CallbackHelper callbackHelper = new CallbackHelper(SampleClass.class, new Class[0]){
			@Override
			protected Object getCallback(Method method) {
				if(method.getDeclaringClass() != Object.class && method.getReturnType() == String.class){
					return new FixedValue(){
						@Override
						public Object loadObject() throws Exception {
							return "hello cglib";
						}
					};
				} else {
					return NoOp.INSTANCE;
				}
			}
		};
		enhancer.setSuperclass(SampleClass.class);
		enhancer.setCallbackFilter(callbackHelper);
		enhancer.setCallbacks(callbackHelper.getCallbacks());
		SampleClass proxy = (SampleClass)enhancer.create();
		System.out.println(proxy.test(null));
		System.out.println(proxy.toString());
		System.out.println(proxy.hashCode());
	}
	
	public static void testImmutableBean() {
		SampleBean bean = new SampleBean();
		bean.setValue("hello");
		SampleBean immutableBean = (SampleBean) ImmutableBean.create(bean);
		System.out.println(immutableBean.getValue());
		//可以通过底层对象来进行修改
		bean.setValue("world");
		System.out.println(immutableBean.getValue());
		//直接修改将throw exception
		immutableBean.setValue("hello world");
	}
	
	public static void testBeanGenerator() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
		BeanGenerator beanGenerator = new BeanGenerator();
		beanGenerator.addProperty("value", String.class);
		Object myBean = beanGenerator.create();
		Method setter = myBean.getClass().getMethod("setValue", String.class);
		setter.invoke(myBean, "hello cglib");
		
		Method getter = myBean.getClass().getMethod("getValue");
		System.out.println(getter.invoke(myBean));
	}
	
	public static void testKeyFactory() {
		SampleKeyFactory keyFactory = (SampleKeyFactory) KeyFactory.create(SampleKeyFactory.class);
		Object key = keyFactory.newInstance("a", 40);
		Object key2 = keyFactory.newInstance("a", 40);
		System.out.println(key);
		System.out.println(key2);
		System.out.println(key == key2);
	}
	
	public static void testMethodDelegate(){
		SampleBean bean = new SampleBean();
		bean.setValue("hello cglib");
		BeanDelegate delegate = (BeanDelegate) MethodDelegate.create(bean, "getValue", BeanDelegate.class);
		System.out.println(delegate.getValueFromDelegate());
	}
	
	public static void testFastClass() throws InvocationTargetException{
		FastClass fastClass = FastClass.create(SampleBean.class);
		FastMethod fastMethod = fastClass.getMethod("getValue", new Class[0]);
		SampleBean bean = new SampleBean();
		bean.setValue("hello world");
		System.out.println(fastMethod.invoke(bean, new Object[0]));
	}
	
	public static void main(String[] args) throws Exception {
//		testFixedValue();
//		testInvocationHander();
//		testCallbackFilter();
//		testImmutableBean();
//		testBeanGenerator();
//		testKeyFactory();
//		testMethodDelegate();
		testFastClass();
	}
	
}
